//SCAR Plugin. Created for SCAR Divi by Kaitnieks & Freddy1990
// currently you can't call SCAR functions from plugin
library WizzyPlugin;

uses
  FastShareMem,
  SysUtils,
  Windows,
  Math,
  Graphics;

{$R *.res}
type TIntegerArray = array of Integer;

type
  TPoint = record
    x,y: Integer;
  end;

  TBox = record
    x1, y1, x2, y2: Integer;
  end;

  TPointArray = array of TPoint;
  T2DPointArray = array of TPointArray;
  
  TRGB32 = packed record
    B, G, R, A: Byte;
  end;
  TRGB32Array = packed array[0..MaxInt div SizeOf(TRGB32) - 1] of TRGB32;
  PRGB32Array = ^TRGB32Array;

const
  flnC=545947;
  fsqrtA:single=0.5;

//---------------------------------------
// Functions to be called from SCAR

function fsqrt(x: Single): Single;
asm
  sub dword ptr x, ($3F800000-flnC)
  fild dword ptr x
  fmul fsqrtA
  fistp dword ptr x
  add dword ptr x,($3F800000-flnC)
  fld x
end;

procedure tSwap(var a, b: TPoint); stdcall;
var
   c: TPoint;
begin
  c := a;
  a := b;
  b := c;
end;

procedure tpaSwap(var a, b: TPointArray); stdcall;
var
   c: TPointArray;
begin
  c := a;
  a := b;
  b := c;
end;

procedure SwapE(var a, b: Extended); stdcall;
var
   c: extended;
begin
  c := a;
  a := b;
  b := c;
end;

procedure RAaSTPAEx(var a: TPointArray; const w, h: Integer); stdcall;
var
   i, c, NoTP, l: Integer;
   t: TPoint;
begin
  NoTP := 0;
  l := High(a);
  for i := 0 to l do
  begin
    for c := 0 to NoTP - 1 do
      if (Abs(a[i].x - a[c].x) <= w) and (Abs(a[i].y - a[c].y) <= h) then
        Break;
    if (c >= NoTP) then
    begin
      t := a[i];
      a[i] := a[NoTP];
      a[NoTP] := t;
      Inc(NoTP);
    end;
  end;
  SetLength(a, NoTP);
end;

procedure RAaSTPA(var a: TPointArray; const Dist: Integer); stdcall;
var
   i, c, NoTP, l: Integer;
   t: TPoint;
begin
  NoTP := 0;
  l := High(a);
  for i := 0 to l do
  begin
    for c := 0 to NoTP - 1 do
      if (Round(fSqrt(Sqr(a[i].x - a[c].x) + Sqr(a[i].y - a[c].y))) <= Dist) then
        Break;
    if (c >= NoTP) then
    begin
      t := a[i];
      a[i] := a[NoTP];
      a[NoTP] := t;
      Inc(NoTP);
    end;
  end;
  SetLength(a, NoTP);
end;

function NearbyPointInArrayEx(const P: TPoint; w, h:Integer; a: TPointArray): Boolean; stdcall;
var
  i, l: Integer;
begin
  Result := False;
  l := High(a);
  for i := 0 to l do
    if (Abs(P.x - a[i].x) <= w) and (Abs(P.y - a[i].y) <= h) then
    begin
      Result := True;
      Exit;
    end;
end;

function NearbyPointInArray(const P: TPoint; Dist:Integer; a: TPointArray): Boolean; stdcall;
var
  i, l: Integer;
begin
  Result := False;
  l := High(a);
  for i := 0 to l do
    if (Round(fSqrt(Sqr(P.x - a[i].x) + Sqr(P.y - a[i].y))) <= Dist) then
    begin
      Result := True;
      Exit;
    end;
end;

function ReArrangeandShortenArrayEx(a: TPointArray; w, h: Integer): TPointArray; stdcall;
var
  i, t, c, l: Integer;
begin
  l := High(a);
  c := 0;
  SetLength(Result, l + 1);
  for i := 0 to l do
  begin
    for t := 0 to c -1 do
      if (Abs(Result[t].x - a[i].x) <= w) and (Abs(Result[t].y - a[i].y) <= h) then
        Break;
    if (t >= c) then
    begin
      Result[c] := a[i];
      Inc(c);
    end;
  end;
  SetLength(Result, c);
end;

function ReArrangeandShortenArray(a: TPointArray; Dist: Integer): TPointArray; stdcall;
var
  i, t, c, l: Integer;
begin
  l := High(a);
  c := 0;
  SetLength(Result, l + 1);
  for i := 0 to l do
  begin
    for t := 0 to c -1 do
      if (Round(fSqrt(Sqr(Result[t].x - a[i].x) + Sqr(Result[t].y - a[i].y))) <= Dist) then
        Break;
    if (t >= c) then
    begin
      Result[c] := a[i];
      Inc(c);
    end;
  end;
  SetLength(Result, c);
end;

function TPAtoATPAEx(TPA: TPointArray; w, h: Integer): T2DPointArray; stdcall;
var
   a, b, c, l: LongInt;
begin
  SetLength(Result, 0);
  l := High(TPA);
  c := 0;
  for a := 0 to l do
  begin
    for b := 0 to c -1 do
      if (Abs(TPA[a].X - Result[b][0].X) <= w) and (Abs(TPA[a].Y - Result[b][0].Y) <= h) then
        Break;
    if (b < c) then
    begin
      SetLength(Result[b], Length(Result[b]) + 1);
      Result[b][High(Result[b])] := TPA[a];
    end else
    begin
      SetLength(Result, c + 1);
      SetLength(Result[c], 1);
      Result[c][0] := TPA[a];
      Inc(c);
    end;
  end;
end;

function TPAtoATPA(TPA: TPointArray; Dist: Integer): T2DPointArray; stdcall;
var
   a, b, c, l: LongInt;
begin
  SetLength(Result, 0);
  l := High(tpa);
  c := 0;
  for a := 0 to l do
  begin
    for b := 0 to c -1 do
      if (Round(fSqrt(Sqr(TPA[a].X - Result[b][0].X) + Sqr(TPA[a].Y - Result[b][0].Y))) <= Dist) then
        Break;
    if (b < c) then
    begin
      SetLength(Result[b], Length(Result[b]) + 1);
      Result[b][High(Result[b])] := TPA[a];
    end else
    begin
      SetLength(Result, c + 1);
      SetLength(Result[c], 1);
      Result[c][0] := TPA[a];
      Inc(c);
    end;
  end;
end;

procedure QuickTPASort(var A: TIntegerArray; var B: TPointArray; iLo, iHi: Integer; SortUp: Boolean);
var
  Lo, Hi, Mid, T: Integer;
  TP: TPoint;
begin
  if (Length(A) <> Length(B)) then Exit;
  Lo := iLo;
  Hi := iHi;
  Mid := A[(Lo + Hi) shr 1];
  repeat
    if SortUp then
    begin
      while (A[Lo] < Mid) do Inc(Lo);
      while (A[Hi] > Mid) do Dec(Hi);
    end else
    begin
      while (A[Lo] > Mid) do Inc(Lo);
      while (A[Hi] < Mid) do Dec(Hi);
    end;
    if (Lo <= Hi) then
    begin
      T := A[Lo];
      A[Lo] := A[Hi];
      A[Hi] := T;
      TP := B[Lo];
      B[Lo] := B[Hi];
      B[Hi] := TP;
      Inc(Lo);
      Dec(Hi);
    end;
  until Lo > Hi;
  if (Hi > iLo) then QuickTPASort(A, B, iLo, Hi, SortUp);
  if (Lo < iHi) then QuickTPASort(A, B, Lo, iHi, SortUp);
end;

procedure QuickATPASort(var A: TIntegerArray; var B: T2DPointArray; iLo, iHi: Integer; SortUp: Boolean);
var
  Lo, Hi, Mid, T: Integer;
  TP: TPointArray;
begin
  if (Length(A) <> Length(B)) then Exit;
  Lo := iLo;
  Hi := iHi;
  Mid := A[(Lo + Hi) shr 1];
  repeat
    if SortUp then
    begin
      while (A[Lo] < Mid) do Inc(Lo);
      while (A[Hi] > Mid) do Dec(Hi);
    end else
    begin
      while (A[Lo] > Mid) do Inc(Lo);
      while (A[Hi] < Mid) do Dec(Hi);
    end;
    if (Lo <= Hi) then
    begin
      T := A[Lo];
      A[Lo] := A[Hi];
      A[Hi] := T;
      TP := B[Lo];
      B[Lo] := B[Hi];
      B[Hi] := TP;
      Inc(Lo);
      Dec(Hi);
    end;
  until Lo > Hi;
  if (Hi > iLo) then QuickATPASort(A, B, iLo, Hi, SortUp);
  if (Lo < iHi) then QuickATPASort(A, B, Lo, iHi, SortUp);
end;

procedure SortTPAFrom(var a: TPointArray; const From: TPoint); stdcall;
var
   i, l: Integer;
   DistArr: TIntegerArray;
begin
  l := High(a);
  if (l < 0) then Exit;
  SetLength(DistArr, l + 1);
  for i := 0 to l do
    DistArr[i] := Round(Sqr(From.x - a[i].x) + Sqr(From.y - a[i].y));
  QuickTPASort(DistArr, a, 0, l, True);
end;

procedure SortATPAFrom(var a: T2DPointArray; const From: TPoint); stdcall;
var
   i, l: Integer;
begin
  l := High(a);
  if (l < 0) then Exit;
  for i := 0 to l do
    SortTPAFrom(a[i], From);
end;

procedure SortATPAFromFirstPoint(var a: T2DPointArray; const From: TPoint); stdcall;
var
   i, l: Integer;
   DistArr: TIntegerArray;
begin
  l := High(a);
  if (l < 0) then Exit;
  SetLength(DistArr, l + 1);
  for i := 0 to l do
    DistArr[i] := Round(Sqr(From.x - a[i][0].x) + Sqr(From.y - a[i][0].y));
  QuickATPASort(DistArr, a, 0, l, True);
end;

procedure InvertTPA(var a: TPointArray); stdcall;
var
   i, l: Integer;
   b: tpointarray;
begin
  l := High(a);
  if (l < 0) then Exit;
  b := Copy(a);
  for i := l downto 0 Do
    a[l - i] := b[i];
end;

procedure InvertATPA(var a: T2DPointArray); stdcall;
var
   i, l: Integer;
   b: T2DPointArray;
begin
  l := High(a);
  if (l < 0) then Exit;
  b := Copy(a);
  for i := l downto 0 do
    a[l - i] := b[i];
end;

function MiddleTPAEx(TPA: TPointArray; var x, y: Integer): Boolean; stdcall;
var
   i, l: Integer;
begin
  Result := False;
  l := High(tpa);
  if (l < 0) then Exit;
  x := 0;
  y := 0;
  for i := 0 to l do
  begin
    x := x + tpa[i].x;
    y := y + tpa[i].y;
  end;
  x := x div (l + 1);
  y := y div (l + 1);
  Result := True;
end;

function MiddleTPA(tpa: TPointArray): TPoint; stdcall;
var
   i, l: Integer;
begin
  l := High(tpa);
  if (l < 0) then Exit;
  Result.x := 0;
  Result.y := 0;
  for i := 0 to l do
  begin
    Result.x := Result.x + tpa[i].x;
    Result.y := Result.y + tpa[i].y;
  end;
  Result.x := Result.x div (l + 1);
  Result.y := Result.y div (l + 1);
end;

procedure SortATPASize(var a: T2DPointArray; const BigFirst: Boolean); stdcall;
var
   i, l: Integer;
   SizeArr: TIntegerArray;
begin
  l := High(a);
  if (l < 0) then Exit;
  SetLength(SizeArr, l + 1);
  for i := 0 to l do
    SizeArr[i] := Length(a[i]);
  QuickATPASort(SizeArr, a, 0, l, not BigFirst);
end;

procedure SortATPAFromSize(var a: T2DPointArray; const Size: Integer; CloseFirst: Boolean); stdcall;
var
   i, l: Integer;
   SizeArr: TIntegerArray;
begin
  l := High(a);
  if (l < 0) then Exit;
  SetLength(SizeArr, l + 1);
  for i := 0 to l do
    SizeArr[i] := Abs(Length(a[i]) - Size);
  QuickATPASort(SizeArr, a, 0, l, CloseFirst);
end;

function CombineTPA(Ar1, Ar2: TPointArray): TPointArray; stdcall;
var
  i, l1, l2: Integer;
begin
  Result := Copy(Ar1);
  l1 := Length(Result);
  l2 := Length(Ar2);
  SetLength(Result, l1 + l2);
  for i := 0 to l2 -1 do
    Result[i + l1] := Ar2[i];
end;

function CombineIntArray(Ar1, Ar2: TIntegerArray): TIntegerArray; stdcall;
var
  i, l1, l2: Integer;
begin
  Result := Copy(Ar1);
  l1 := Length(Result);
  l2 := Length(Ar2);
  SetLength(Result, l1 + l2);
  for i := 0 to l2 -1 do
    Result[i + l1] := Ar2[i];
end;

function InIntArrayEx(a: TIntegerArray; var Where: Integer; const Number: Integer): Boolean; stdcall;
var
  i, l: Integer;
begin
  Result := False;
  l := High(a);
  for i := 0 to l do
    if (a[i] = Number) then
    begin
      Where := i;
      Result := True;
      Exit;
    end;
end;

function InIntArray(a: TIntegerArray; Number: Integer): Boolean; stdcall;
var
  i, l: Integer;
begin
  Result := False;
  l := High(a);
  for i := 0 to l do
    if (a[i] = Number) then
    begin
      Result := True;
      Exit;
    end;
end;

procedure ClearSameIntegers(var a: TIntegerArray); stdcall;
var
  i, t, c, l: Integer;
  b: TIntegerArray;
begin
  b := Copy(a);
  l := High(b);
  c := 0;
  for i := 0 to l do
  begin
    for t := 0 to c -1 do
      if (b[i] = a[t]) then
        Break;
    if (t >= c) then
    begin
      a[c] := b[i];
      Inc(c);
    end;
  end;
  SetLength(a, c);
end;

procedure ClearSameIntegersAndTPA(var a: TIntegerArray; var p: TPointArray); stdcall;
var
  i, t, c, l: Integer;
  b: TIntegerArray;
begin
  b := Copy(a);
  l := High(b);
  c := 0;
  for i := 0 to l do
  begin
    for t := 0 to c -1 do
      if (b[i] = a[t]) then
        Break;
    if (t >= c) then
    begin
      SetLength(a, c +1);
      a[c] := b[i];
      p[c] := p[i];
      Inc(c);
    end;
  end;
  SetLength(p, c);
  SetLength(a, c);
end;

function SplitTPAEx(arr: TPointArray; w, h: Integer): T2DPointArray; stdcall;
var
  t1, t2, c, ec, tc, l: Integer;
  tpa: TPointArray;
begin
  tpa := Copy(arr);
  l := High(tpa);
  if (l < 0) then Exit;
  SetLength(Result, l + 1);
  c := 0;
  ec := 0;
  while ((l - ec) >= 0) do
  begin
    SetLength(Result[c], 1);
    Result[c][0] := tpa[0];
    tpa[0] := tpa[l - ec];
    Inc(ec);
    tc := 1;
    t1 := 0;
    while (t1 < tc) do
    begin
      t2 := 0;
      while (t2 <= (l - ec)) do
      begin
        if (Abs(Result[c][t1].x - tpa[t2].x) <= w) and (Abs(Result[c][t1].y - tpa[t2].y) <= h) then
        begin
          SetLength(Result[c], tc +1);
          Result[c][tc] := tpa[t2];
          tpa[t2] := tpa[l - ec];
          Inc(ec);
          Inc(tc);
          Dec(t2);
        end;
        Inc(t2);
      end;
      Inc(t1);
    end;
    Inc(c);
  end;
  SetLength(Result, c);
end;

function SplitTPA(arr: TPointArray; Dist: Integer): T2DPointArray; stdcall;
var
  t1, t2, c, ec, tc, l: Integer;
  tpa: TPointArray;
begin
  tpa := Copy(arr);
  l := High(tpa);
  if (l < 0) then Exit;
  SetLength(Result, l + 1);
  c := 0;
  ec := 0;
  while ((l - ec) >= 0) do
  begin
    SetLength(Result[c], 1);
    Result[c][0] := tpa[0];
    tpa[0] := tpa[l - ec];
    Inc(ec);
    tc := 1;
    t1 := 0;
    while (t1 < tc) do
    begin
      t2 := 0;
      while (t2 <= (l - ec)) do
      begin
        if (Round(fSqrt(Sqr(Result[c][t1].x - tpa[t2].x) + Sqr(Result[c][t1].y - tpa[t2].y))) <= Dist) then
        begin
          SetLength(Result[c], tc +1);
          Result[c][tc] := tpa[t2];
          tpa[t2] := tpa[l - ec];
          Inc(ec);
          Inc(tc);
          Dec(t2);
        end;
        Inc(t2);
      end;
      Inc(t1);
    end;
    Inc(c);
  end;
  SetLength(Result, c);
end;

procedure FilterPointsPie(var Points: TPointArray; const SD, ED, MinR, MaxR: Extended; Mx, My: Integer); stdcall;
const
  i180Pi = 57.29577951;
var
   G: TPointArray;
   I, L, T: Integer;
   D, StartD, EndD: Extended;
   cWise: Boolean;
begin
  T := High(Points);
  if (T < 0) then Exit;
  SetLength(G, T + 1);
  L := 0;
  StartD := SD;
  EndD := ED;
  cWise := StartD > EndD;
  while StartD > 360.0 do
    StartD := StartD - 360.0;
  while EndD > 360.0 do
    EndD := EndD - 360.0;
  while StartD < 0.0 do
    StartD := StartD + 360.0;
  while EndD < 0.0 do
    EndD := EndD + 360.0;
  if StartD > EndD then
    SwapE(StartD, EndD);
  for I := 0 to T do
  begin
    D := fSqrt(Sqr(Points[I].X - Mx) + Sqr(Points[I].Y - My));
    if( D <= MinR) or (D >= MaxR) then
      Continue;
    D := (ArcTan2(Points[I].Y - My, Points[I].X - Mx) * i180Pi) + 90;
    if D < 0.0 then
      D := D + 360.0;
    if (not ((StartD <= D) and (EndD >= D))) xor CWise then
      Continue;
    G[L] := Points[I];
    Inc(L);
  end;
  SetLength(G, L);
  Points := G;
end;

function RemoveDistTPointArray(x, y, dist: Integer; ThePoints: TPointArray; RemoveHigher: Boolean): TPointArray; stdcall;
var
  I, L, LL: integer;
begin;
  L := 0;
  LL := Length(ThePoints) -1;
  SetLength(Result, LL + 1);
  if RemoveHigher then
  begin;
    for I := 0 to LL do
      if not (Round(fSqrt(sqr(ThePoints[i].x - x)+sqr(ThePoints[i].y - y))) > Dist) then
      begin;
        Result[L] := ThePoints[i];
        L := L + 1;
      end;
  end else
  begin;
    for I := 0 to LL do
      if not (Round(fSqrt(sqr(ThePoints[i].x - x)+sqr(ThePoints[i].y - y))) < Dist) then
      begin;
        Result[L] := ThePoints[i];
        L := L + 1;
      end;
  end;
  SetLength(Result,L);
end;

function GetATPABounds(ATPA: T2DPointArray): TBox; stdcall;
var
  I,II,L2,L : Integer;
begin;
  L := High(ATPA);
  if (l < 0) then Exit;
  For I := 0 to L do
    if Length(ATPA[I]) > 0 then
    begin;
      Result.x1 := ATPA[I][0].x;
      Result.y1 := ATPA[I][0].y;
      Result.x2 := ATPA[I][0].x;
      Result.y2 := ATPA[I][0].y;
    end;
  for I := 0 to L do
  begin;
    L2 := High(ATPA[I]);
    for II := 0 to L2 do
    begin;
      if ATPA[i][II].x > Result.x2 then
        Result.x2 := ATPA[i][II].x
      else if ATPA[i][II].x < Result.x1 then
        Result.x1 := ATPA[i][II].x;
      if ATPA[i][II].y > Result.y2 then
        Result.y2 := ATPA[i][II].y
      else if ATPA[i][II].y < Result.y1 then
        Result.y1 := ATPA[i][II].y;
    end;
  end;
end;

function GetTPABounds(TPA: TPointArray): TBox; stdcall;
var
  I,L : Integer;
begin;
  L := High(TPA);
  if (l < 0) then Exit;
  Result.x1 := TPA[0].x;
  Result.y1 := TPA[0].y;
  Result.x2 := TPA[0].x;
  Result.y2 := TPA[0].y;
  for I:= 1 to L do
  begin;
    if TPA[i].x > Result.x2 then
      Result.x2 := TPA[i].x
    else if TPA[i].x < Result.x1 then
      Result.x1 := TPA[i].x;
    if TPA[i].y > Result.y2 then
      Result.y2 := TPA[i].y
    else if TPA[i].y < Result.y1 then
      Result.y1 := TPA[i].y;
  end;
end;

function FindTPAinTPA(SearchTPA, TotalTPA: TPointArray; var Matches: TPointArray): Boolean; stdcall;
var
  Len, I,II,LenSearch,xOff,yOff : integer;
  tx,ty,MatchCount : integer;
  Screen : Array of Array of Boolean;
  ScreenBox,SearchBox : TBox;
begin;
  Result := False;
  Len := High(TotalTPA);
  LenSearch := High(SearchTPA);
  if LenSearch < 0 then Exit;
  if Len < LenSearch then Exit;
  MatchCount := 0;
  ScreenBox := GetTPABounds(TotalTPA);
  SearchBox := GetTPABounds(SearchTPA);
  try
    SetLength(Screen,ScreenBox.x2 + 1,ScreenBox.y2 + 1);
  except
    Exit;
  end;
  if (SearchBox.x1 > 0) or (SearchBox.y1 > 0) then
  begin;
    for I := 0 to LenSearch do
    begin;
      SearchTPA[I].x := SearchTPA[I].x - SearchBox.x1;
      SearchTPA[I].y := SearchTPA[I].y - SearchBox.y1;
    end;
    SearchBox.x2 := SearchBox.x2 - SearchBox.x1;
    SearchBox.y2 := SearchBox.y2 - SearchBox.y1;
    SearchBox.x1 := 0;
    SearchBox.y1 := 0;
  end;
  xOff := SearchBox.x2;
  yOff := SearchBox.y2;
  for I := 0 to LenSearch do
  begin;
    if (SearchTPA[I].x = 0) and (SearchTPA[I].y < yOff) then
        yOff := SearchTPA[I].y;
    if (SearchTPA[I].y = 0) and (SearchTPA[I].x < xOff) then
        xOff := SearchTPA[I].x;
  end;
  for I := 0 to Len do
    Screen[TotalTPA[I].x][TotalTPA[I].y] := True;
  for I := 0 to Len do
  begin;
    tx := TotalTPA[I].x - xOff;
    ty := TotalTPA[I].y;// - yOff;
    if tx > 0 then
      if ty > 0 then
        if ((SearchBox.x2 + tx) <= ScreenBox.x2) and ((SearchBox.y2 + ty) <= ScreenBox.y2) then
          begin;
            For II := 0 to LenSearch do
              if Screen[tx + SearchTPA[II].x ][ty + SearchTPA[II].y] = False then
                Break;
            if II > LenSearch then
            begin;
              MatchCount := MatchCount + 1;
              SetLength(Matches,MatchCount);
              Matches[MatchCount - 1].x := TotalTPA[I].x;
              Matches[MatchCount - 1].y := TotalTPA[I].y;
            end;
          end;
  end;
  if (MatchCount > 0) then
    Result := True;
end;

function FindTextTPAinTPA(Height : integer; SearchTPA, TotalTPA: TPointArray; var Matches: TPointArray): Boolean; stdcall;
var
  Len, I,II,LenSearch,LenTPA,xOff,yOff,x,y: integer;
  tx,ty,MatchCount : integer;
  Screen : Array of Array of Boolean;
  ScreenBox,SearchBox : TBox;
  InversedTPA : TPointArray;
begin;
  Result := False;
  Len := High(TotalTPA);
  LenSearch := High(SearchTPA);
  if LenSearch < 0 then Exit;
  if Len < LenSearch then Exit;
  MatchCount := 0;
  xOff := -5;
  yOff := 0;
  ScreenBox := GetTPABounds(TotalTPA);
  SearchBox := GetTPABounds(SearchTPA);
  if height > SearchBox.y2 then
    Screenbox.y2 := Screenbox.y2 + (height - SearchBox.y2);  
  SearchBox.y2 := Height;
  SetLength(Screen, SearchBox.x2 + 1,Searchbox.y2 + 1);
  SetLength(InversedTPA,(SearchBox.x2 + 1) * (Searchbox.y2 + 1));
  for I := 0 to LenSearch do
    Screen[ SearchTPA[I].x,SearchTPA[I].y] := True;
  LenTPA := -1;
  for y := 0 to SearchBox.y2 do
    for x := 0 to SearchBox.x2 do
      if Screen[X][Y] = False then
      begin;
        LenTPA := LenTPA + 1;
        InversedTPA[LenTPA].x := x;
        InversedTPA[LenTPA].y := y;
      end;
  for x := 0 to SearchBox.x2 do
  begin;
    for y := 0 to SearchBox.y2 do
      if Screen[x][y] = True then
      begin;
        xOff := x;
        yOff := y;
        Break;
      end;
    if xOff >= 0 then
      Break;
  end;
  try
    SetLength(Screen,0);
    SetLength(Screen,ScreenBox.x2 + 1,ScreenBox.y2 + 1);
  except
    Exit;
  end;
  for I := 0 to Len do
    Screen[TotalTPA[I].x][TotalTPA[I].y] := True;
  for I := 0 to Len do
  begin;
    tx := TotalTPA[I].x - xOff;
    ty := TotalTPA[I].y - yOff;
    if tx > 0 then
      if ty > 0 then
        if ((SearchBox.x2 + tx) <= ScreenBox.x2) and ((SearchBox.y2 + ty) <= ScreenBox.y2) then
          begin;
            For II := 0 to LenSearch do
              if Screen[tx + SearchTPA[II].x ][ty + SearchTPA[II].y] = False then
                Break;
            if (II > LenSearch) then
            begin;
              For II := 0 to LenTPA do
                if Screen[tx + InversedTPA[II].x ][ty + InversedTPA[II].y] = True then
                  Break;
              if (II > LenTPA) then
              begin;
                MatchCount := MatchCount + 1;
                SetLength(Matches,MatchCount);
                Matches[MatchCount - 1].x := TotalTPA[I].x;
                Matches[MatchCount - 1].y := TotalTPA[I].y;
              end;
            end;
          end;
  end;
  if (MatchCount > 0) then
    Result := True;
end;

function FindGapsTPA(TPA: TPointArray; MinPixels: Integer): T2DPointArray; stdcall;
var
  Len,TotalLen,LenRes,I,II,III : integer;
  Screen : Array of Array of Boolean;
  Height,Width : Integer;
  Box : TBox;
begin;
  Len := High(TPA);
  if Len < 0 then exit;
  Box := GetTPABounds(TPA);
  Height := Box.y2 - Box.y1;
  Width := Box.x2 - Box.x1;
  LenRes := 0;
  III := 0;
  try
    SetLength(Screen,Width + 1,Height + 1);
  except
    Exit;
  end;
  For I := 0 to Len do
    Screen[TPA[I].x - Box.x1][TPA[I].y - Box.y1] := True;
  SetLength(result,1);
  SetLength(Result[0],Len+1);
  TotalLen := 0;
  for I := 0 to Width do
  begin;
    for II := 0 to Height do
      if Screen[I][II]=True then
      begin;
        Result[TotalLen][LenRes].x := I + Box.x1;
        Result[TotalLen][LenRes].y := II + Box.y1;
        LenRes := LenRes + 1;
        III := I;
      end;
    if LenRes = 0 then
      III := I
    else
    if (I - III) > MinPixels then
    begin;
      III := I;
      SetLength(Result[TotalLen],LenRes);
      LenRes := 0;
      TotalLen := TotalLen + 1;
      SetLength(Result,TotalLen + 1);
      SetLength(Result[TotalLen],Len + 1);
    end;
  end;
  SetLength(Result[TotalLen],LenRes);
end;

Function CreateTPAFromBMP( BmpDC : HDC):  TPointArray;Stdcall;
var
  x,y,L,I : Integer;
  Box : TBox;
  Bmp : Windows.TBitmap;
  Bitmappie : TBitmap;
  HBmp : Windows.HBitmap;
  LengthLine : LongInt;
  ScanLine : PRGB32Array;
begin;
  HBmp := GetCurrentObject(BmpDC,OBJ_BITMAP);
  GetObject(HBmp,SizeOf(Bmp),@Bmp);
  Bitmappie := TBitmap.Create;
  Bitmappie.PixelFormat := pf32bit;
  Bitmappie.Width := Bmp.bmWidth;
  Bitmappie.Height := Bmp.bmHeight;
  SetLength(Result,Bmp.bmWidth * Bmp.bmHeight);
  BitBlt(Bitmappie.Canvas.Handle, 0, 0, Bmp.bmWidth,Bmp.bmHeight, BmpDC, 0, 0, SRCCOPY);
  ScanLine := Bitmappie.Scanline[0];
  LengthLine := (Longint(Bitmappie.Scanline[1]) - Longint(ScanLine)) div 4;
  L := -1;
  Bmp.bmWidth := Bmp.bmWidth - 1;
  Bmp.bmHeight := Bmp.bmHeight - 1;
  For y := 0 to Bmp.bmHeight do
    For x := 0 to Bmp.bmWidth do
      if Scanline[y * LengthLine + x].r = 255 then
      begin;
        L := L + 1;
        Result[L].x := x;
        Result[L].y := y;
      end;
  SetLength(Result,L + 1);
  Box := GetTPABounds(Result);
  if (Box.x1 = 0) and (Box.y1 = 0) then
    Exit;
  L := High(Result);
  For I := 0 to L do
  begin;
    Result[I].x := Result[I].x - Box.x1;
    Result[I].y := Result[I].y - Box.y1;
  end;
end;

procedure SortCircleWise(var tpa: TPointArray; const cx, cy, StartDegree: Integer; SortUp, ClockWise: Boolean); stdcall;
const
  i180Pi = 57.29577951;
var
  i, l, td, sd: Integer;
  Dist, Deg: TIntegerArray;
begin
  l := Length(tpa);
  if (l = 0) then Exit;
  sd := StartDegree;
  while (sd > 360) do
    sd := (sd - 360);
  sd := (360 - sd);
  SetLength(Dist, l);
  SetLength(Deg, l);
  for i := 0 to l -1 do
    Dist[i] := Round(Hypot(tpa[i].x - cx, tpa[i].y - cy));
  QuickTPASort(Dist, tpa, 0, l -1, SortUp);
  if (l = 1) then Exit;
  for i := 0 to l -1 do
  begin
    td := Round(ArcTan2(tpa[i].y - cy, tpa[i].x - cx) * i180Pi) + 90;
    if (td < 0) then
      td := td + 360;
    if ClockWise then
      Deg[i] := Round(sd + td) mod 360
    else
      Deg[i] := 360 - Round(sd + td) mod 360;
  end;
  i := 1;
  td := 0;
  Dec(l);
  while (i < l) do
  begin
    while (i < l) and (Abs(Dist[td] - Dist[i]) <= 1) do Inc(i);
    QuickTPASort(Deg, tpa, td, i, False);
    Inc(i);
    td := i;
  end;
  if (td < l) then
    QuickTPASort(Deg, tpa, td, l, False);
end;

procedure LinearSort(var tpa: TPointArray; cx, cy, sd: Integer; SortUp: Boolean); stdcall;
const
  i180Pi = 57.29577951;
var
  i, l, td: Integer;
  Dist, Deg: TIntegerArray;
begin
  l := Length(tpa);
  if (l = 0) then Exit;
  while (sd > 360) do
    sd := (sd - 360);
  SetLength(Dist, l);
  SetLength(Deg, l);
  for i := 0 to l -1 do
  begin
    td := Round(ArcTan2(tpa[i].y - cy, tpa[i].x - cx) * i180Pi) + 90;
    if (td < 0) then
      td := td + 360;
    Deg[i] := Min(Abs(sd - td), Min(Abs(sd - (td + 360)), Abs((sd + 360) - td)))
  end;
  QuickTPASort(Deg, tpa, 0, l -1, True);
  if (l = 1) then Exit;
  for i := 0 to l -1 do
    Dist[i] := Round(Hypot(tpa[i].x - cx, tpa[i].y - cy));
  i := 1;
  td := 0;
  Dec(l);
  while (i < l) do
  begin
    while (i < l) and (Abs(Deg[td] - Deg[i]) <= 3) do Inc(i);
    QuickTPASort(Dist, tpa, td, i, SortUp);
    Inc(i);
    td := i;
  end;
  if (td < l) then
    QuickTPASort(Dist, tpa, td, l, SortUp);
end;

Function MergeATPA(ATPA : T2DPointArray)  : TPointArray;stdcall;
var
  I,II, Len, TempL,CurrentL : integer;
begin;
  Len := High(ATPA);
  CurrentL := 0;
  For I:= 0 to Len do
  begin;
    TempL := High(ATPA[I]);
    if TempL < 0 then
      Continue;
    TempL := Templ + CurrentL + 1;
    Setlength(Result, TempL+1);
    For II := CurrentL to TempL do
      Result[II] := ATPA[I][II - CurrentL];
    CurrentL := TempL;
  end;
  SetLength(Result,CurrentL);
end;

Procedure DrawTPACanvas(const TPA : TPointArray;Color : Integer; Canvas : TCanvas);stdcall;
var
  Hi,I : Integer;
begin;
  Hi := High(TPA);
  For I := 0 to Hi do
    Canvas.Pixels[TPA[I].x,TPA[I].y] := Color;
end;

Procedure DrawATPACanvas(const ATPA : T2DPointArray;Color : Integer; Canvas : TCanvas);stdcall;
var
  Hi,High2,I,II : Integer;
begin;
  Hi := High(ATPA);
  For I := 0 to Hi do
  begin;
    High2 := High(ATPA[I]);
    For II := 0 to High2 do
      Canvas.Pixels[ATPA[I][II].x,ATPA[I][II].y] := Color;
  end;
end;

function TPAFromBox(var Box : TBox) : TPointArray; stdcall;
var
  x,y : integer;
  l : integer;
begin;
  SetLength(Result, (Box.x2 - Box.x1 + 1) * (Box.y2 - Box.y1 + 1));
  l := 0;
  For x := box.x1 to Box.x2 do
    for y := box.y1 to box.y2 do
    begin;
      Result[l].x := x;
      Result[l].y := y;
      inc(l);
    end;
end;

Function RotatePoints(Const P: TPointArray; A, cx, cy: Extended): TPointArray ; stdcall;

Var
   I, L: Integer;

Begin
  L := High(P);
  SetLength(Result, L + 1);
  For I := 0 To L Do
  Begin
    Result[I].X := Trunc(cx + cos(A) * (p[i].x - cx) - sin(A) * (p[i].y - cy));
    Result[I].Y := Trunc(cy + sin(A) * (p[i].x - cx) + cos(A) * (p[i].y - cy));
  End;
  // I recon it's faster than Point().
End;

Function RotatePoint(Const p: TPoint; angle, mx, my: Extended): TPoint; stdcall;

Begin
  Result.X := Trunc(mx + cos(angle) * (p.x - mx) - sin(angle) * (p.y - my));
  Result.Y := Trunc(my + sin(angle) * (p.x - mx) + cos(angle) * (p.y- my));
End;

function FindTPAEdges(p: TPointArray): TPointArray; stdcall;
var
  b: array of array of Boolean;
  i, x, y, l, c: Integer;
  Box: TBox;
begin
  SetLength(Result, 0);
  l := Length(p);
  if (l = 0) then Exit;
  Box := GetTPABounds(p);
  x := (Box.x2 - Box.x1) + 3;
  y := (Box.y2 - Box.y1) + 3;
  SetLength(b, x);
  for i := 0 to x -1 do
    SetLength(b[i], y);
  for i := 0 to l -1 do
    b[p[i].x +1 - Box.x1][p[i].y +1 - Box.y1] := True;
  SetLength(Result, l);
  c := 0;
  for i := 0 to l -1 do
  begin
    x := -1;
    while (x <= 1) do
    begin
      for y := -1 to 1 do
        try
          if not b[p[i].x + 1 + x - Box.x1][p[i].y + 1 + y - Box.y1] then
          begin
            Result[c] := p[i];
            Inc(c);
            x := 2;
            Break;
          end;
        except end;
      Inc(x);
    end;
  end;
  SetLength(Result, c);
end;

//********************************
//  Change this accordingly to your function count

function GetFunctionCount(): Integer; stdcall; export;
begin
  Result := 45;
end;

//*******************************
//  Change this accordingly to your function definitions

function GetFunctionInfo(x: Integer; var ProcAddr: Pointer; var ProcDef: PChar): Integer; stdcall;
begin
  case x of
    0:
      begin
        ProcAddr := @tSwap;
        StrPCopy(ProcDef, 'procedure tSwap(var a, b: TPoint);');
      end;
    1:
      begin
        ProcAddr := @ClearSameIntegers;
        StrPCopy(ProcDef, 'procedure ClearSameIntegers(var a: TIntegerArray);');
      end;
    2:
      begin
        ProcAddr := @ClearSameIntegersAndTPA;
        StrPCopy(ProcDef, 'procedure ClearSameIntegersAndTPA(var a: TIntegerArray; var c: TPointArray);');
      end;
    3:
      begin
        ProcAddr := @CombineIntArray;
        StrPCopy(ProcDef, 'function CombineIntArray(Ar1, Ar2: TIntegerArray): TIntegerArray;');
      end;
    4:
      begin
        ProcAddr := @CombineTPA;
        StrPCopy(ProcDef, 'function CombineTPA(First, Second: TPointArray): TPointArray;');
      end;
    5:
      begin
        ProcAddr := @FilterPointsPie;
        StrPCopy(ProcDef, 'procedure FilterPointsPie(var Points: TPointArray; SD, ED, MinR, MaxR: Extended; Mx, My: Integer);');
      end;
    6:
      begin
        ProcAddr := @FindGapsTPA;
        StrPCopy(ProcDef, 'function FindGapsTPA(TPA : TPointArray; MinPixels: Integer): T2DPointArray;');
      end;
    7:
      begin
        ProcAddr := @FindTPAinTPA;
        StrPCopy(ProcDef, 'function FindTPAinTPA(SearchTPA, TotalTPA: TPointArray; var Matches: TPointArray): Boolean;');
      end;
    8:
      begin
        ProcAddr := @GetTPABounds;
        StrPCopy(ProcDef, 'function GetTPABounds(TPA: TPointArray): TBox;');
      end;
    9:
      begin
        ProcAddr := @InIntArrayEx;
        StrPCopy(ProcDef, 'function InIntArrayEx(a: TIntegerArray; var Where: Integer; Number: Integer): Boolean;');
      end;
    10:
      begin
        ProcAddr := @InIntArray;
        StrPCopy(ProcDef, 'function InIntArray(a: TIntegerArray; Number: Integer): Boolean;');
      end;
    11:
      begin
        ProcAddr := @InvertTPA;
        StrPCopy(ProcDef, 'procedure InvertTPA(var a: TPointArray);');
      end;
    12:
      begin
        ProcAddr := @InvertATPA;
        StrPCopy(ProcDef, 'procedure InvertATPA(var a: T2DPointArray);');
      end;
    13:
      begin
        ProcAddr := @MiddleTPA;
        StrPCopy(ProcDef, 'function MiddleTPA(tpa: TPointArray): TPoint;');
      end;
    14:
      begin
        ProcAddr := @MiddleTPAEx;
        StrPCopy(ProcDef, 'function MiddleTPAEx(TPA: TPointArray; var x, y: Integer): Boolean;');
      end;
    15:
      begin
        ProcAddr := @NearbyPointInArrayEx;
        StrPCopy(ProcDef, 'function NearbyPointInArrayEx(P: TPoint; w, h:Integer; a: TPointArray): Boolean;');
      end;
    16:
      begin
        ProcAddr := @NearbyPointInArray;
        StrPCopy(ProcDef, 'function NearbyPointInArray(P: TPoint; Dist:Integer; a: TPointArray): Boolean;');
      end;
    17:
      begin
        ProcAddr := @RAaSTPAEx;
        StrPCopy(ProcDef, 'procedure RAaSTPAEx(var a: TPointArray; w, h: Integer);');
      end;
    18:
      begin
        ProcAddr := @RAaSTPA;
        StrPCopy(ProcDef, 'procedure RAaSTPA(var a: TPointArray; Dist: Integer);');
      end;
    19:
      begin
        ProcAddr := @ReArrangeandShortenArrayEx;
        StrPCopy(ProcDef, 'function ReArrangeandShortenArrayEx(a: TPointArray; w, h: Integer): TPointArray;');
      end;
    20:
      begin
        ProcAddr := @ReArrangeandShortenArray;
        StrPCopy(ProcDef, 'function ReArrangeandShortenArray(a: TPointArray; Dist: Integer): TPointArray;');
      end;
    21:
      begin
        ProcAddr := @RemoveDistTPointArray;
        StrPCopy(ProcDef, 'function RemoveDistTPointArray(x, y, dist: Integer; ThePoints: TPointArray; RemoveHigher: Boolean):');
      end;
    22:
      begin
        ProcAddr := @SortATPAFrom;
        StrPCopy(ProcDef, 'procedure SortATPAFrom(var a: T2DPointArray; From: TPoint);');
      end;
    23:
      begin
        ProcAddr := @SortATPAFromFirstPoint;
        StrPCopy(ProcDef, 'procedure SortATPAFromFirstPoint(var a: T2DPointArray; From: TPoint);');
      end;
    24:
      begin
        ProcAddr := @SortATPAFromSize;
        StrPCopy(ProcDef, 'procedure SortATPAFromSize(var a: T2DPointArray; Size: Integer; CloseFirst: Boolean);');
      end;
    25:
      begin
        ProcAddr := @SortTPAFrom;
        StrPCopy(ProcDef, 'procedure SortTPAFrom(var a: TPointArray; From: TPoint);');
      end;
    26:
      begin
        ProcAddr := @SortATPASize;
        StrPCopy(ProcDef, 'procedure SortATPASize(var a: T2DPointArray; BigFirst: Boolean);');
      end;
    27:
      begin
        ProcAddr := @SplitTPA;
        StrPCopy(ProcDef, 'function SplitTPA(arr: TPointArray; Dist: Integer): T2DPointArray;');
      end;
    28:
      begin
        ProcAddr := @SplitTPAEx;
        StrPCopy(ProcDef, 'function SplitTPAEx(OldArray: TPointArray; w, h: Integer): T2DPointArray;');
      end;
    29:
      begin
        ProcAddr := @SwapE;
        StrPCopy(ProcDef, 'procedure SwapE(var a, b: Extended);');
      end;
    30:
      begin
        ProcAddr := @tpaSwap;
        StrPCopy(ProcDef, 'procedure tpaSwap(var a, b: TPointArray);');
      end;
    31:
      begin
        ProcAddr := @TPAtoATPAEx;
        StrPCopy(ProcDef, 'function TPAtoATPAEx(TPA: TPointArray; w, h: Integer): T2DPointArray;');
      end;
    32:
      begin
        ProcAddr := @TPAtoATPA;
        StrPCopy(ProcDef, 'function TPAtoATPA(TPA: TPointArray; Dist: Integer): T2DPointArray;');
      end;
    33:
      begin
        ProcAddr := @CreateTPAFromBMP;
        StrPCopy(ProcDef, 'Function CreateTPAFromBMP( BmpDC : HDC) :  TPointArray;');
      end;
    34:
      begin
        ProcAddr := @FindTextTPAinTPA;
        StrPCopy(ProcDef, 'function FindTextTPAinTPA(Height : integer; SearchTPA, TotalTPA: TPointArray; var Matches: TPointArray): Boolean;');
      end;
    35:
      begin
        ProcAddr := @SortCircleWise;
        StrPCopy(ProcDef, 'procedure SortCircleWise(var tpa: TPointArray; const cx, cy, StartDegree: Integer; SortUp, ClockWise: Boolean)');
      end;
    36:
      begin
        ProcAddr := @LinearSort;
        StrPCopy(ProcDef, 'procedure LinearSort(var tpa: TPointArray; cx, cy, sd: Integer; SortUp: Boolean);');
      end;
    37:
      begin
        ProcAddr := @MergeATPA;
        StrPCopy(ProcDef, 'Function MergeATPA(ATPA : T2DPointArray): TPointArray;');
      end;
    38:
      begin
        ProcAddr := @GetATPABounds;
        StrPCopy(ProcDef, 'function GetATPABounds(ATPA: T2DPointArray): TBox;');
      end;
    39:
      begin
        ProcAddr := @DrawATPACanvas;
        StrPCopy(ProcDef, 'Procedure DrawATPACanvas(const ATPA : T2DPointArray;Color : Integer; Canvas : TCanvas);');
      end;
    40:
      begin
        ProcAddr := @DrawTPACanvas;
        StrPCopy(ProcDef, 'Procedure DrawTPACanvas(const TPA : TPointArray;Color : Integer; Canvas : TCanvas);');
      end;
    41:
      begin
        ProcAddr := @TPAFromBox;
        StrPCopy(ProcDef, 'function TPAFromBox(var Box : TBox) : TPointArray;');
      end;
    42:
      begin
        ProcAddr := @RotatePoints;
        StrPCopy(ProcDef, 'Function RotatePoints(Const P: TPointArray; A, cx, cy: Extended): TPointArray;');
      end;
    43:
      begin
        ProcAddr := @RotatePoint;
        StrPCopy(ProcDef, 'Function RotatePoint(Const p: TPoint; angle, mx, my: Extended): TPoint;');
      end;
    44:
      begin
        ProcAddr := @FindTPAEdges;
        StrPCopy(ProcDef, 'function FindTPAEdges(p: TPointArray): TPointArray;');
      end;
 else
    x := -1;
  end;
  Result := x;
end;


//***************************
// Don't change below this
exports GetFunctionCount;
exports GetFunctionInfo;

end.

